<template>
  <div>
    <!-- 地图容器 -->
    <div id="container"></div>
    <suspendedWindow ref="startWindowRef" text="发" :state="'昆山市'" :leftBgColor="'#e3e3e3'"></suspendedWindow>
    <suspendedWindow ref="endWindowRef" text="收"  :state="'合肥市'" :leftBgColor="'#64af5d'"></suspendedWindow>
    <suspendedWindow ref="CurrentPositionWindowRef"   :state="'你的包裹当前位置'" :rightBgColor="'#64af5d'"></suspendedWindow>

  </div>
</template>

<script>
import AMapLoader from '@amap/amap-jsapi-loader'
import suspendedWindow from './suspendedWindow.vue'

export default {
  name: 'map-view',
  components: {
    suspendedWindow
  },
  data () {
    return {
      // 车辆轨迹点数组
      marker: [
        [116.478935, 39.997761], [116.478939, 39.997825],
        [116.478912, 39.998549], [116.478912, 39.998549],
        [116.478998, 39.998555], [116.478998, 39.998555],
        [116.479282, 39.99856], [116.479658, 39.998528],
        [116.480151, 39.998453], [116.480784, 39.998302],
        [116.480784, 39.998302], [116.481149, 39.998184],
        [116.481573, 39.997997], [116.481863, 39.997846],
        [116.482072, 39.997718], [116.482362, 39.997718],
        [116.483633, 39.998935], [116.48367, 39.998968],
        [116.484648, 39.999861]
      ],
      traveledPath: [], // 已行驶路径
      remainingPath: [], // 未行驶路径
      animationId: null, // 动画ID
      AMap: null, // 高德地图实例
      map: null, // 地图实例
      markerInstance: null, // 车辆标记实例
      traveledPolyline: null, // 已行驶路线实例
      remainingPolyline: null, // 未行驶路线实例
      lastPosition: null, // 上一帧位置
      startTime: 0, // 动画开始时间
      duration: 4000, // 动画持续时间(ms)
      logisticsAArrival: [116.483633, 39.998935] // 物流当前位置
    }
  },
  mounted () {
    this.$nextTick(() => {
      // 确保子组件已经渲染
      const startWindowRef = this.$refs.startWindowRef.$refs.startWindowRef // 发货的弹窗信息endWindowRef
      if (startWindowRef) {
        const width = startWindowRef.offsetWidth // 或者使用clientWidth, 根据需求
        const height = startWindowRef.offsetHeight // 或者使用clientWidth, 根据需求
        this.startWindowRefWidthHeight = {
          width,
          height
        }
        // console.log('子组件内部盒子的宽度:', width)
        // console.log('子组件内部盒子的高度:', height)
      }
    })

    this.initAMap()
    this.traveledPath = [this.marker[0]] // 初始化已行驶路径
  },
  beforeDestroy () {
    this.clearAnimation()
    if (this.map) {
      this.map.destroy()
    }
  },
  methods: {

    // 查询当前车子在总路程数组里的下标位置
    findMarkerIndex () {
      return this.marker.findIndex(item => item[0] === this.logisticsAArrival[0] && item[1] === this.logisticsAArrival[1])
    },
    /**
     * 初始化高德地图
     */
    initAMap () {
      // 安全配置
      window._AMapSecurityConfig = {
        securityJsCode: '0ff1cbff627c63298435735ea4f4eb37'
      }

      // 加载高德地图API
      AMapLoader.load({
        key: 'bcdfa81a13468e4bce53c354fd41b5f8',
        version: '2.0',
        plugins: ['AMap.Marker', 'AMap.Polyline', 'AMap.GeometryUtil']
      }).then((AMap) => {
        this.AMap = AMap
        this.initMap(AMap)
      }).catch((e) => {
        console.error('地图加载失败:', e)
      })
    },

    /**
     * 初始化地图
     * @param {Object} AMap - 高德地图API实例
     */
    initMap (AMap) {
      // 创建地图实例
      this.map = new AMap.Map('container', {
        zoom: 17,
        center: [116.478935, 39.997761],
        mapStyle: 'amap://styles/whitesmoke'
      })
      this.map.setFeatures(['road', 'point', 'bg', 'building']) // 多个种类要素显示
      // 创建车辆标记

      const car = new this.AMap.Icon({
        size: new this.AMap.Size(50, 52),
        image: 'https://a.amap.com/jsapi_demos/static/demo-center-v2/car.png',
        anchor: 'center'
        // imageOffset: new this.AMap.Pixel(-5, -3)
        // imageSize: new this.AMap.Size(135, 40)
      })

      this.markerInstance = new AMap.Marker({
        position: this.marker[0],
        icon: car,
        offset: new AMap.Pixel(-38, -26)
        // anchor: 'top-center'
      })
      this.map.add(this.markerInstance)

      // 创建已行驶路线(绿色)
      this.traveledPolyline = new AMap.Polyline({
        path: this.traveledPath,
        strokeColor: '#00aa00',
        strokeWeight: 6,
        lineJoin: 'round'
      })
      this.map.add(this.traveledPolyline)

      // 创建未行驶路线(浅蓝色)
      this.remainingPolyline = new AMap.Polyline({
        path: [...this.marker],
        strokeColor: '#4a90e2',
        strokeWeight: 6,
        lineJoin: 'round'
      })
      this.map.add(this.remainingPolyline)

      // 添加起点终点标记
      this.addStartEndMarkers()

      // 开始动画
      this.startAnimation()
    },

    /**
     * 添加起点和终点标记
     */
    addStartEndMarkers () {
      // 起点标记
      const startIcon = new this.AMap.Icon({
        size: new this.AMap.Size(25, 34),
        image: '//a.amap.com/jsapi_demos/static/demo-center/icons/dir-marker.png',
        imageOffset: new this.AMap.Pixel(-9, -3),
        imageSize: new this.AMap.Size(135, 40)
      })
      const startMarker = new this.AMap.Marker({
        position: this.marker[0],
        icon: startIcon,
        offset: new this.AMap.Pixel(-13, -30),
        title: '起点'
      })
      this.map.add(startMarker)

      // 终点标记
      const endIcon = new this.AMap.Icon({
        size: new this.AMap.Size(25, 34),
        image: '//a.amap.com/jsapi_demos/static/demo-center/icons/dir-marker.png',
        imageOffset: new this.AMap.Pixel(-96, -3),
        imageSize: new this.AMap.Size(135, 40)
      })
      const endMarker = new this.AMap.Marker({
        position: this.marker[this.marker.length - 1],
        icon: endIcon,
        offset: new this.AMap.Pixel(-13, -30),
        title: '终点'
      })
      this.map.add(endMarker)

      const startWindowRef = this.$refs.startWindowRef.$el

      // 开始位置的弹框
      const startWindow = new this.AMap.Marker({
        position: this.marker[0],
        content: startWindowRef,
        title: '起点弹窗',
        offset: new this.AMap.Pixel(-(+this.$refs.startWindowRef.$refs.startWindowRef.offsetWidth) / 2, -(+this.$refs.startWindowRef.$refs.startWindowRef.offsetHeight) * 2)
      })
      this.map.add(startWindow)

      const endWindowRef = this.$refs.endWindowRef.$el
      // 终点位置的弹框
      const endWindow = new this.AMap.Marker({
        position: this.marker[this.marker.length - 1],
        content: endWindowRef,
        title: '终点弹窗',
        // 获取子组件盒子的宽度高度
        offset: new this.AMap.Pixel(-(+this.$refs.endWindowRef.$refs.startWindowRef.offsetWidth) / 2, -(+this.$refs.endWindowRef.$refs.startWindowRef.offsetHeight) * 2)
      })
      this.map.add(endWindow)

      // 车头上的弹窗
      const CurrentPositionWindowRef = this.$refs.CurrentPositionWindowRef.$el

      this.CurrentPositionWindow = new this.AMap.Marker({
        // position: this.marker[this.marker.length - 1],
        content: CurrentPositionWindowRef,
        title: '车头上的弹窗',
        offset: new this.AMap.Pixel(-(+this.$refs.CurrentPositionWindowRef.$refs.startWindowRef.offsetWidth) / 2, -(+this.$refs.CurrentPositionWindowRef.$refs.startWindowRef.offsetHeight) * 1.8)
      })
      this.map.add(this.CurrentPositionWindow)
    },

    /**
     * 开始动画
     */
    startAnimation () {
      this.clearAnimation()
      this.startTime = Date.now()
      this.lastPosition = this.marker[0]

      const animate = () => {
        const elapsed = Date.now() - this.startTime
        const progress = Math.min(elapsed / this.duration, 1)

        // 计算当前位置
        const { currentPos, currentLatAndLon } = this.calculatePosition(progress)
        this.CurrentPositionWindow.setPosition(currentPos)
        // console.log(currentLatAndLon)
        // 判断车子有没有到指定位置到了就退出动画
        if (JSON.stringify(currentLatAndLon) === JSON.stringify(this.logisticsAArrival)) return

        // 更新车辆位置
        this.markerInstance.setPosition(currentPos)

        // 平滑移动地图中心
        this.map.setCenter(currentPos, true, 100)

        // 精确更新路径
        this.updatePathsPrecisely(currentPos)

        // 计算并更新车辆方向
        this.updateVehicleDirection(currentPos)

        // 继续动画或结束
        if (progress < 1) {
          this.animationId = requestAnimationFrame(animate)
        }
      }

      this.animationId = requestAnimationFrame(animate)
    },

    /**
     * 精确更新路径
     * @param {Array} currentPos - 当前位置[lng, lat]
     */
    updatePathsPrecisely (currentPos) {
      let closestSegmentIndex = 0
      let closestRatio = 0
      let minDistance = Infinity

      // 查找最近的路径段
      for (let i = 1; i < this.marker.length; i++) {
        const start = this.marker[i - 1]
        const end = this.marker[i]
        this.start = start

        // 计算点到线段的投影
        const ratio = this.calculateProjectionRatio(currentPos, start, end)
        const projectedPoint = [
          start[0] + ratio * (end[0] - start[0]),
          start[1] + ratio * (end[1] - start[1])
        ]

        // 计算距离
        const dx = currentPos[0] - projectedPoint[0]
        const dy = currentPos[1] - projectedPoint[1]
        const distance = Math.sqrt(dx * dx + dy * dy)

        // 更新最近点
        if (distance < minDistance) {
          minDistance = distance
          closestSegmentIndex = i - 1
          closestRatio = ratio
        }
      }

      // 分割路径
      const traveled = this.marker.slice(0, closestSegmentIndex + 1)
      if (closestRatio > 0) {
        const segmentStart = this.marker[closestSegmentIndex]
        const segmentEnd = this.marker[closestSegmentIndex + 1]
        const intermediatePoint = [
          segmentStart[0] + closestRatio * (segmentEnd[0] - segmentStart[0]),
          segmentStart[1] + closestRatio * (segmentEnd[1] - segmentStart[1])
        ]
        traveled.push(intermediatePoint)
      }
      traveled.push(currentPos)

      const remaining = [currentPos, ...this.marker.slice(closestSegmentIndex + 1)]

      // 更新折线[116.480784, 39.998302]
      this.traveledPolyline.setPath(traveled)
      // console.log(currentPos)

      this.remainingPolyline.setPath(remaining)
    },

    /**
     * 计算点在线段上的投影比例
     * @param {Array} point - 点坐标
     * @param {Array} segmentStart - 线段起点
     * @param {Array} segmentEnd - 线段终点
     * @return {Number} 投影比例(0-1)
     */
    calculateProjectionRatio (point, segmentStart, segmentEnd) {
      const dx = segmentEnd[0] - segmentStart[0]
      const dy = segmentEnd[1] - segmentStart[1]
      const length2 = dx * dx + dy * dy

      if (length2 === 0) return 0

      const dot = (point[0] - segmentStart[0]) * dx + (point[1] - segmentStart[1]) * dy
      return Math.min(1, Math.max(0, dot / length2))
    },

    /**
     * 更新车辆方向
     * @param {Array} currentPos - 当前位置
     */
    updateVehicleDirection (currentPos) {
      const dx = currentPos[0] - this.lastPosition[0]
      const dy = currentPos[1] - this.lastPosition[1]

      // 只有移动距离足够大时才更新方向(优化性能)
      if (Math.sqrt(dx * dx + dy * dy) > 0.00001) {
        const angle = (Math.atan2(dx, dy) * 180 / Math.PI + 360) % 360
        this.markerInstance.setAngle(angle)
        this.lastPosition = currentPos
      }
    },

    /**
     * 根据进度计算路径上的位置
     * @param {Number} progress - 进度(0-1)
     * @return {Array} 当前位置[lng, lat]
     */
    calculatePosition (progress) {
      const totalDist = this.calculateTotalDistance()
      const targetDist = totalDist * progress
      let accumulated = 0

      for (let i = this.findMarkerIndex() - 4; i < this.marker.length; i++) {
        const segDist = this.AMap.GeometryUtil.distance(this.marker[i - 1], this.marker[i])
        if (accumulated + segDist >= targetDist) {
          const ratio = (targetDist - accumulated) / segDist
          const x = this.marker[i - 1][0]
          const y = this.marker[i - 1][1]

          return {
            currentPos: [
              (this.marker[i - 1][0] + ratio * (this.marker[i][0] - this.marker[i - 1][0])),
              (this.marker[i - 1][1] + ratio * (this.marker[i][1] - this.marker[i - 1][1]))
            ],
            // 当前车站经过的经纬度
            currentLatAndLon: [x, y]
          }
        }
        accumulated += segDist
      }
      return this.marker[this.marker.length - 1]
    },

    /**
     * 计算路径总长度
     * @return {Number} 路径总长度(米)
     */
    calculateTotalDistance () {
      return this.marker.reduce((acc, point, i) =>
        i > 0 ? acc + this.AMap.GeometryUtil.distance(this.marker[i - 1], point) : 0, 0)
    },

    /**
     * 清除动画
     */
    clearAnimation () {
      if (this.animationId) {
        cancelAnimationFrame(this.animationId)
        this.animationId = null
      }
    }
  }
}
</script>

<style scoped>
#container {
  width: 100%;
  height: 80vh;
  padding: 0;
  margin: 0;
}
</style>
